﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GraphicsStyleDlg.h"
#include "ICategory.h"
#include "UiCommonDialog.h"
#include "IJournalUiObject.h"

#include "IUiDocument.h"
#include "IUiView.h"
#include "IPublishConfig.h"
#include "IDocument.h"
#include "GmStyleSheetHelper.h"
#include "ImportedObjectStylePage.h"
#include "ICategoryLibrary.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "ICategoryAndGraphicsStyleFilter.h"
#include "UniIdentity.h"
#include "GraphicsStyleTable.h"
#include "qevent.h"
#include "IJournalUiEvent.h"
#include "JournalUtils.h"
#include "IGraphicsStyleManager.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

GraphicsStyleDlg::GraphicsStyleDlg(IUiDocument* pUIDoc, IUiView* currentView, std::wstring& title)
    : QDialog(nullptr, Qt::FramelessWindowHint | Qt::WindowSystemMenuHint
    | Qt::WindowMinMaxButtonsHint)
    , m_wpUIDoc(pUIDoc)
    , m_wpCurrentView(currentView)
    , m_opApplyBntJournalUiObject(nullptr)
    , m_opApplyBntMouseEvent(nullptr)
{
    m_ui.setupUi(this);
    resize(1150, 800);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUIDoc, L"无效参数",L"GDMPLab",L"2024-03-30");
    gcmp::IDocument* pDoc = pUIDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"doc 为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDocument = pDoc;

    // 设置对话框样式
    std::wstring styleSheetStr = GmStyleSheetHelper::Instance()->GetCurrentStyleData();
    setStyleSheet(QString::fromStdWString(styleSheetStr));
    m_ui.gbmp_title->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    m_ui.gbmp_title->setIconVisible(false);
    m_ui.gbmp_title->setMaxButtonVisible(false);
    m_ui.gbmp_title->setMinButtonVisible(false);
    m_ui.gbmp_title->setText(QString::fromStdWString(title));
    this->setProperty("use_gbmp_title", true);
    connect(m_ui.gbmp_title, &GmTitleBar::closeRequested, this, &GraphicsStyleDlg::reject);
    connect(m_ui.gbmp_title, &GmTitleBar::moveRequested, this, &GraphicsStyleDlg::onMoveRequested);
 
    // 响应按钮
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_ui.applyBnt != nullptr, L"m_ui.applyBnt 为空",L"GDMPLab",L"2024-03-30");
    m_ui.applyBnt->button(QDialogButtonBox::Ok)->setObjectName(QStringLiteral("buttonOK"));
    m_ui.applyBnt->button(QDialogButtonBox::Cancel)->setObjectName(QStringLiteral("buttonCancel"));
    //m_ui.applyBnt->button(QDialogButtonBox::Apply)->setObjectName(QStringLiteral("buttonApply"));
    //m_ui.applyBnt->button(QDialogButtonBox::RestoreDefaults)->setObjectName(QStringLiteral("buttonRestoreDefaults"));
    m_ui.applyBnt->button(QDialogButtonBox::Ok)->setText(QString::fromStdWString(GBMP_TR(L"确定")));
    m_ui.applyBnt->button(QDialogButtonBox::Cancel)->setText(QString::fromStdWString(GBMP_TR(L"取消")));
    //m_ui.applyBnt->button(QDialogButtonBox::Apply)->setText(QString::fromStdWString(GBMP_TR(L"应用")));
    //m_ui.applyBnt->button(QDialogButtonBox::RestoreDefaults)->setText(QString::fromStdWString(GBMP_TR(L"恢复默认")));

    QObject::connect(m_ui.applyBnt, SIGNAL(accepted()), this, SLOT(OnApply()));


    //日志模块对GraphicsStyleDlg内applyBnt操作的record，需要在输出CmdProjectMaterialSet\CmdViewMaterialSet两条command语句之后
    if (m_ui.applyBnt && m_ui.applyBnt->parent())
    {
        m_opApplyBntJournalUiObject = gcmp::IJournalUiObject::Create();
        DBG_WARN_AND_RETURN_VOID_UNLESS(m_opApplyBntJournalUiObject, L"gcmp::IJournalUiObject::Create()返回空指针",L"GDMPLab",L"2024-03-30");
        m_opApplyBntJournalUiObject->SetUiObejct((QObject*)m_ui.applyBnt->button(QDialogButtonBox::Ok));
        OwnerPtr<gcmp::IJournalUiEvent> opUIEvent = gcmp::IJournalUiEvent::Create();
        DBG_WARN_AND_RETURN_VOID_UNLESS(opUIEvent, L"gcmp::IJournalUiEvent::Create()返回空指针",L"GDMPLab",L"2024-03-30");
        m_opApplyBntMouseEvent = NEW_AS_OWNER_PTR(QMouseEvent, QEvent::MouseButtonPress, QPoint(0, 0), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
        opUIEvent->SetUiEvent((QEvent*)m_opApplyBntMouseEvent.get());
        int64_t dlgId = this->winId();
        bool isOk = gcmp::JournalUtils::RegisterUiDataPreRecordFunction(m_opApplyBntJournalUiObject.get(), opUIEvent.get(), RecordMaterialDatas(dlgId));
    }

    // 清空Table
    ClearAllGsTables();
 
    bool isFamilyDoc = false;
    if (pDocument->IsFamilyDocument())
    {
        isFamilyDoc = true;
    }
    std::vector<UniIdentity> allCategories = ICategoryAndGraphicsStyleFilter::GetCategoryAndGraphicsStyleFilter()->GetCategoriesForObjectStyleSetting(pDoc);
    std::vector<std::wstring> groupNames = ICategoryAndGraphicsStyleFilter::GetCategoryAndGraphicsStyleFilter()->GetAllObjectStyleSettingGroups(isFamilyDoc);
    FOR_EACH(name, groupNames)
    {
        std::vector<UniIdentity> curGroup;
        FOR_EACH(id, allCategories)
        {
            if (name == ICategoryAndGraphicsStyleFilter::GetCategoryAndGraphicsStyleFilter()->GetObjectStyleSettingGroupForCategory(id, isFamilyDoc))
            {
                curGroup.push_back(id);
            }
        }
        m_opPages.push_back(NEW_AS_OWNER_PTR(GraphicsStyleTable, m_wpUIDoc.Get(), m_wpCurrentView.Get(), this, curGroup, GBMP_TR(name)));
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_ui.tabWidget != nullptr, L"m_ui.tabWidget is nullptr",L"GDMPLab",L"2024-03-30");
    QObject::connect(m_ui.tabWidget, SIGNAL(currentChanged(int)), this, SLOT(OnTabChanged(int)));
    // 内部样式Table
    const IConfigRecord* pInHouseModeConfigRecord = IPublishConfig::GetConfigRecord(PublishConfigRecordNames::InHouseMode);
    if (pInHouseModeConfigRecord && pInHouseModeConfigRecord->IsInternalIdentifyCodeValue())
    {
        std::vector<gcmp::UniIdentity> categories_4_internal = ICategoryAndGraphicsStyleFilter::GetCategoryAndGraphicsStyleFilter()->GetInternalCategoriesForObjectStyleSetting(pDoc);
        if (categories_4_internal.size() > 0)
        {
            m_opPages.push_back(NEW_AS_OWNER_PTR(GraphicsStyleTable, m_wpUIDoc.Get(), m_wpCurrentView.Get(), this, categories_4_internal, GBMP_TR(L"内部使用对象")));
        }
    }

    if (ICategoryAndGraphicsStyleFilter::GetCategoryAndGraphicsStyleFilter()->ShowImportedCategoryGroupForObjectStyleSetting())
    {
        // 导入对象
        if (!pDoc->IsFamilyDocument())
        {
            std::map<std::wstring, std::list<gcmp::UniIdentity>> importedObjectCategories;
            GetImportedObjectCategories(pDoc, importedObjectCategories);
            if (IModelView* pModelView = GetModelView())
            {
                OwnerPtr<ImportedObjectModelViewStylePage> opImportedObjectModelViewPage = NEW_AS_OWNER_PTR(ImportedObjectModelViewStylePage, this);
                opImportedObjectModelViewPage->InitUI(pModelView, importedObjectCategories);
                m_opPages.push_back(TransferOwnership(opImportedObjectModelViewPage));
            }
            else
            {
                OwnerPtr<ImportedObjectDocumentStylePage> opImportedObjectDocumentPage = NEW_AS_OWNER_PTR(ImportedObjectDocumentStylePage, this);
                opImportedObjectDocumentPage->InitUI(pDoc, importedObjectCategories);
                m_opPages.push_back(TransferOwnership(opImportedObjectDocumentPage));
            }
        }
    }
    /////////////////////////////////////////////
    // GsTable to TabUi
    /////////////////////////////////////////////
    UpdateTabUi();
    RefreshBtnStatus();
}

void GraphicsStyleDlg::UpdateTabUi()
{
    ClearAllTabPages();
    for (int i = 0; i < (int)m_opPages.size(); ++i)
    {
        IGraphicsStylePage* pPage = m_opPages[i].get();
        if (m_opPages[i] == nullptr)
        {
            continue;
        }

        QWidget* pTabPage = NEW_AS_QT_CHILD(QWidget, m_ui.tabWidget);
        QVBoxLayout* pVLayout = NEW_AS_QT_CHILD(QVBoxLayout, pTabPage);
        pVLayout->addWidget(pPage->GetWidgetFW());
        pPage->GetWidgetFW()->setParent(pTabPage);
        m_ui.tabWidget->addTab(pTabPage, QString::fromStdWString(pPage->GetLabel()));
    }
}

void GraphicsStyleDlg::changeEvent(QEvent * event)
{
    QEvent::Type enType = event->type();
    if (event->type() == QEvent::ActivationChange)
    {
        if (isActiveWindow())
        {
            m_ui.gbmp_title->setObjectName(QString::fromStdWString(L"gbmp_title"));
        }
        else
        {
            m_ui.gbmp_title->setObjectName(QString::fromStdWString(L"gbmp_title_dactive"));
        }
        style()->unpolish(m_ui.gbmp_title);
        style()->polish(m_ui.gbmp_title);
    }
}

IModelView* GraphicsStyleDlg::GetModelView() const
{
    return m_wpCurrentView ? m_wpCurrentView->GetModelView() : nullptr;
}

void GraphicsStyleDlg::OnApply()
{
    for (int i = 0; i < (int)m_opPages.size(); ++i)
    {
        if (m_opPages[i] == nullptr)
        {
            continue;
        }
        m_opPages[i]->OnApplied();
    }

    //材质设置command语句需要在applyBnt的点击操作之前记录
    //gcmp::IJournalManager::Get()->RecordWidgetEventFromCacheImmediately();

    //刷新视图
    //m_wpUIDoc->UpdateView(false);
    m_wpUIDoc->UpdateViewByVisibilityConditionChanged();
}

void GraphicsStyleDlg::OnTabChanged(int iIndex)
{
    RefreshBtnStatus();
}

void GraphicsStyleDlg::onMoveRequested(const QPoint& cursorPos, const QPoint& offset)
{
    Q_UNUSED(cursorPos);
    move(pos() + offset);
}

void GraphicsStyleDlg::RefreshBtnStatus()
{

}

GraphicsStyleDlg::~GraphicsStyleDlg()
{
    OwnerPtr<gcmp::IJournalUiEvent> opUIEvent = gcmp::IJournalUiEvent::Create();
    DBG_WARN_AND_RETURN_VOID_UNLESS(opUIEvent, L"gcmp::IJournalUiEvent::Create()返回空指针",L"GDMPLab",L"2024-03-30");
    opUIEvent->SetUiEvent((QEvent*)m_opApplyBntMouseEvent.get());
    JournalUtils::UnregisterUiDataPreRecordFunction(m_opApplyBntJournalUiObject.get(), opUIEvent.get());
}

void GraphicsStyleDlg::AddTabPage(gcmp::OwnerPtr<IGraphicsStylePage> opPage)
{
    m_opPages.push_back(TransferOwnership(opPage));
}

void GraphicsStyleDlg::AddGraphicsStyleTable(const std::vector<gcmp::UniIdentity>& categories, const std::wstring& label)
{
    std::vector<UniIdentity> categoriesNeat;
    categoriesNeat.insert(categoriesNeat.end(), categories.begin(), categories.end());

    m_opPages.push_back(NEW_AS_OWNER_PTR(GraphicsStyleTable, m_wpUIDoc.Get(), m_wpCurrentView.Get(),
        this, categoriesNeat, label));
}

void GraphicsStyleDlg::ClearAllTabPages()
{
    if (m_ui.tabWidget == nullptr)
    {
        return;
    }
    m_ui.tabWidget->clear();
}

void GraphicsStyleDlg::ClearAllGsTables()
{
    if ((int)m_opPages.size() <= 0)
    {
        return;
    }
    m_opPages.clear();
}

void GraphicsStyleDlg::ResetAll()
{
    ClearAllTabPages();
    ClearAllGsTables();
}


bool GraphicsStyleDlg::GetImportedObjectCategories(IDocument* pDoc, std::map<std::wstring, std::list<gcmp::UniIdentity>>& categories)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    categories.clear();

    std::set<UniIdentity> allCategoriesSet = GetAllCategoriesWithGStyles(pDoc);
    std::vector<UniIdentity> allCategories;
    std::copy(allCategoriesSet.begin(), allCategoriesSet.end(), std::back_inserter(allCategories));

    FOR_EACH(uid, allCategories)
    {
        const ICategory* pCategory = ICategoryLibrary::Get(pDoc)->GetCategory(uid);
        DBG_WARN_AND_CONTINUE_UNLESS(pCategory, L"pCategory为空",L"GDMPLab",L"2024-03-30");

        if (pCategory->GetParentUniIdentity() != BuiltInCategoryUniIdentities::BICU_IMPORTED_CAD_OBJECT)
        {
            continue;
        }

        std::wstring objectName, layerName;
        ImportedObjectStylePageUtils::GetFamilyNameAndLayerNameFromCategory(pCategory, objectName, layerName);

        auto itr = categories.find(objectName);
        if (itr == categories.end())
        {
            std::list<gcmp::UniIdentity> uids;
            uids.push_back(uid);
            auto itr = categories.insert(std::make_pair(objectName, uids));
            DBG_WARN_AND_CONTINUE_UNLESS(itr.second, L"objectName已经存在",L"GDMPLab",L"2024-03-30");
        }
        else
        {
            std::list<gcmp::UniIdentity>& uids = itr->second;
            uids.push_back(uid);
        }
    }

    return true;
}

std::set<UniIdentity> GraphicsStyleDlg::GetAllCategoriesWithGStyles(IDocument* pDoc)
{
    std::set<UniIdentity> allCategoriesWithGStyles;
    std::vector<const ICategory*> allCategoriesInDoc = ICategoryLibrary::Get(pDoc)->GetAllCategories();
    FOR_EACH(pCurCategory, allCategoriesInDoc)
    {
        const UniIdentity& categoryUid = pCurCategory->GetUniIdentity();
        ElementId gstyleId = pDoc->GetGraphicsStyleManager()->GetGraphicsStyleIdByCategoryUid(categoryUid);
        if (gstyleId.IsValid())
            allCategoriesWithGStyles.insert(categoryUid);
    }

    return allCategoriesWithGStyles;
}

void GraphicsStyleDlg::RecordMaterialDatas::operator()()
{
    QWidget *pWidget = QWidget::find(m_dlgId);
    GraphicsStyleDlg *pDlg = dynamic_cast<GraphicsStyleDlg*>(pWidget);
    if (pDlg)
    {
        for (int i = 0; i < (int)pDlg->m_opPages.size(); ++i)
        {
            if (pDlg->m_opPages[i] == nullptr)
            {
                continue;
            }
            pDlg->m_opPages[i]->RecordMaterialDatas();
        }
    }
}
